package com.haojiang.mh.widget.chart;

import android.content.Context;
import android.graphics.*;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.haojiang.mh.R;
import com.haojiang.mh.service.entity.SleepTimeChartBean;
import com.haojiang.mh.service.entity.StartEndBean;
import com.haojiang.mh.utils.MUtil;
import com.haojiang.mh.utils.SizeUtil;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 渐变cover+时间Y轴+圆角柱状图（间断）
 * 当前用在《月报--睡眠时间分布》
 */
public class MonthSleepTimeChartView extends View {

    private TextPaint textPaint;//文字Paint
    //坐标、柱子、背景、线条画笔
    private Paint coordinatePaint, columnPaint, bgPaint, linePaint;
    //View 的宽高、默认宽高
    private int width, height, defaultWidth, defaultHeight;
    //X轴坐标点数量、X轴高度、X轴文字高度
    private int xCoordinateNum, xAxisHeight, xAxisTextHeight;
    private float xItemWidth, yItemHeight;//x间隔宽度、y间隔高度
    private int xLeftPadding, xRightPadding, paddingTop;//X轴左右padding、View顶部padding
    private int yAxisWidth, yAxisTextHeight;//Y轴宽度、Y轴文字高度
    //通用、周末、线条、背景 颜色
    private int commonColor, sundayColor, lineColor, bgColor;
    private int columnGraTopColor, columnGraBottomColor;//柱子顶部、底部渐变颜色值
    private int BgGraTopColor, BgGraBottomColor;//背景顶部、底部渐变颜色值
    private int drawHeight, columnWidth;//绘制高度、柱子宽度
    private int bottomY;//Y轴底部起点
    private int xAxisTextSize, yAxisTextSize;//X轴文字、Y轴文字大小
    private LinearGradient shader;//渐变
    private RectF rectF = new RectF();//渐变
    private List<SleepTimeChartBean> beanList;//数据集

    public MonthSleepTimeChartView(Context context) {
        this(context, null);
    }

    public MonthSleepTimeChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MonthSleepTimeChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        xAxisHeight = SizeUtil.dp2px(context, 3);
        xAxisTextHeight = SizeUtil.dp2px(context, 30);
        yAxisWidth = SizeUtil.dp2px(context, 30);
        yAxisTextHeight = SizeUtil.dp2px(context, 20);
        drawHeight = SizeUtil.dp2px(context, 140);
        paddingTop = SizeUtil.dp2px(context, 10);
        xLeftPadding = SizeUtil.dp2px(context, 30);
        xRightPadding = SizeUtil.dp2px(context, 10);
        columnWidth = SizeUtil.dp2px(context, 2);

        defaultWidth = SizeUtil.dp2px(context, 340);
        defaultHeight = paddingTop + drawHeight + xAxisHeight + xAxisTextHeight;

        xAxisTextSize = SizeUtil.sp2px(context, 12);
        yAxisTextSize = SizeUtil.sp2px(context, 10);

        commonColor = getResources().getColor(R.color.white_half);
        sundayColor = getResources().getColor(R.color.purple_3);
        lineColor = getResources().getColor(R.color.white) & 0x19FFFFFF;
        bgColor = getResources().getColor(R.color.grey_5) & 0x4CFFFFFF;
        columnGraTopColor = getResources().getColor(R.color.purple_3);
        columnGraBottomColor = getResources().getColor(R.color.purple_4);
        BgGraTopColor = getResources().getColor(R.color.white) & 0x00FFFFFF;
        BgGraBottomColor = getResources().getColor(R.color.white) & 0x4CFFFFFF;

        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextAlign(Paint.Align.CENTER);

        coordinatePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        coordinatePaint.setStyle(Paint.Style.FILL);
        coordinatePaint.setColor(commonColor);

        columnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        columnPaint.setStyle(Paint.Style.FILL);

        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setColor(lineColor);
        linePaint.setStrokeWidth(2);

        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setColor(bgColor);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (beanList == null || beanList.isEmpty()) return;

        xCoordinateNum = beanList.size();
        xItemWidth = (float) (width - xLeftPadding - xRightPadding - yAxisWidth) / (xCoordinateNum - 1);
        yItemHeight = (float) drawHeight / 24;
        bottomY = paddingTop + drawHeight;

        drawXAxis(canvas);

        drawCover(canvas);

        drawYAxis(canvas);

        drawSegmentColumn(canvas);
    }

    /**
     * 绘制X轴
     */
    private void drawXAxis(Canvas canvas) {
        textPaint.setTextSize(xAxisTextSize);
        for (int i = 0; i < xCoordinateNum; i++) {
            SleepTimeChartBean bean = beanList.get(i);
            if (i % 7 != 0) continue;
            canvas.drawLine(
                    xLeftPadding + xItemWidth * i,
                    bottomY,
                    xLeftPadding + xItemWidth * i,
                    bottomY + xAxisHeight,
                    coordinatePaint
            );
            textPaint.setColor(bean.isCurrMonth() ? sundayColor : commonColor);
            canvas.drawText(
                    bean.getDay(),
                    xLeftPadding + xItemWidth * i,
                    SizeUtil.getBaseLine(textPaint, height, xAxisTextHeight),
                    textPaint
            );
        }
    }

    /**
     * 绘制最佳睡眠区  22:00-07:00
     */
    private void drawCover(Canvas canvas) {
        float top = paddingTop + 11 * yItemHeight;
        float bottom = paddingTop + 20 * yItemHeight;
        canvas.drawLine(0, top, width, top, linePaint);
        bgPaint.setShader(null);
        canvas.drawRect(0, top, width, bottom, bgPaint);
        canvas.drawLine(0, bottom, width, bottom, linePaint);
        shader = new LinearGradient(0, top, 0, bottom, BgGraTopColor, BgGraBottomColor, Shader.TileMode.CLAMP);
        bgPaint.setShader(shader);
        int weekNum = (xCoordinateNum - 1) / 7;
        for (int i = 0; i < weekNum; i++) {
            if (i % 2 != 0) continue;
            float left = xLeftPadding + xItemWidth * 7 * i;
            float right = left + xItemWidth * 7;
            canvas.drawRect(left, top, right, bottom, bgPaint);
        }
    }

    /**
     * 绘制Y轴
     */
    private void drawYAxis(Canvas canvas) {
        textPaint.setColor(commonColor);
        textPaint.setTextSize(yAxisTextSize);
        for (int i = 0; i < 25; i++) {//从上至下
            canvas.drawCircle(width - yAxisWidth, bottomY - yItemHeight * i, 3, coordinatePaint);
            if (i % 3 != 0) continue;
            float yTextBaseLine = bottomY - yItemHeight * i + yAxisTextHeight * 0.5f;
            canvas.drawText(
                    String.format(Locale.getDefault(), "%02d:00", (i + 18) % 24),
                    width - yAxisWidth * 0.5f,
                    SizeUtil.getBaseLine(textPaint, yTextBaseLine, yAxisTextHeight),
                    textPaint
            );
        }
    }

    /**
     * 绘制分段柱状条
     */
    private void drawSegmentColumn(Canvas canvas) {
        for (int i = 0; i < beanList.size(); i++) {
            List<StartEndBean> line = beanList.get(i).getLine();
            if (line == null || line.isEmpty()) continue;
            float bottom = bottomY - line.get(0).getStart() * drawHeight * 1.0f / (24 * 3600);
            float top = bottomY - line.get(line.size() - 1).getEnd() * drawHeight * 1.0f / (24 * 3600);
            shader = new LinearGradient(0, bottom, 0, top, columnGraBottomColor, columnGraTopColor, Shader.TileMode.CLAMP);
            columnPaint.setShader(shader);
            for (int j = 0; j < line.size(); j++) {
                if (line.get(j).isNull()) continue;
                rectF.set(
                        xLeftPadding + xItemWidth * i - columnWidth * 0.5f,
                        bottomY - line.get(j).getEnd() * drawHeight * 1.0f / (24 * 3600),
                        xLeftPadding + xItemWidth * i + columnWidth * 0.5f,
                        bottomY - line.get(j).getStart() * drawHeight * 1.0f / (24 * 3600)
                );
                canvas.drawRoundRect(rectF, columnWidth * 0.5f, columnWidth * 0.5f, columnPaint);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(
                getMeasuredLength(widthMeasureSpec, true),
                getMeasuredLength(heightMeasureSpec, false)
        );
    }

    private int getMeasuredLength(int length, boolean isWidth) {
        int specMode = MeasureSpec.getMode(length);
        int specSize = MeasureSpec.getSize(length);
        int size;
        int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
        if (specMode == MeasureSpec.EXACTLY) {
            size = specSize;
        } else if (specMode == MeasureSpec.UNSPECIFIED) {
            size = isWidth ? defaultWidth : defaultHeight;
        } else {
            size = isWidth ? padding + defaultWidth : padding + defaultHeight;
            if (specMode == MeasureSpec.AT_MOST) {
                size = Math.min(size, specSize);
            }
        }
        return size;
    }

    /**
     * 更新数据集
     */
    public void setChartData(List<SleepTimeChartBean> data) {
        if (beanList == null) beanList = new ArrayList<>();
        beanList.clear();
        if (data != null && !data.isEmpty()) {
            beanList.addAll(data);
            getCompleteMonthData();
        }
        invalidate();
    }

    /**
     * 获取完整月相关数据集
     */
    private void getCompleteMonthData() {
        SleepTimeChartBean bean = beanList.get(0);
        int[] ymd = MUtil.INSTANCE.getYearMonthDay(bean.getDate());
        Calendar cal = Calendar.getInstance();
        cal.set(ymd[0], ymd[1] - 1, ymd[2]);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
            addBeanList(simpleDateFormat.format(new Date(cal.getTimeInMillis())), true);
        }
        cal.set(ymd[0], ymd[1], ymd[2]);
        while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
            addBeanList(simpleDateFormat.format(new Date(cal.getTimeInMillis())), false);
            cal.add(Calendar.DAY_OF_MONTH, 1);
        }
        addBeanList(simpleDateFormat.format(new Date(cal.getTimeInMillis())), false);
    }

    /**
     * 添加Bean
     */
    private void addBeanList(String date, boolean isBefore) {
        SleepTimeChartBean msb = new SleepTimeChartBean();
        msb.setDate(date);
        msb.setCurrMonth(false);
        if (isBefore) {
            beanList.add(0, msb);
        } else {
            beanList.add(msb);
        }
    }
}
